/*
 * nmatc.c
 *
 *  Created on: Mar 31, 2009
 *      Author: Marco Luisi
 */

#include "sysmacro.h"
#include "nmat_protocol.h" //temporaneo
#include "matrix.h" // chiedere
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>

#define FOREVER for(;;) // non serve qui?
#define N 255 //risettare questo valore

//da capire quali globali e quali no.. PER TUTTI
char *username;
char *login;
char *buffer;
char *to_server;
char *from_server;
char cmd[N]; // oppure mallocarlo ogni volta?
matrix **mats; //stabilire se qui solo i nomi delle matrici
char **ctokens; // capire dove metterla

char *cmdline;

int pid;
int servpipe; //rinomniare magari
int in;
int out;
int auth;
/*
 *  uniformare i nomi delle pipe in tutti i sorgenti
 */

//da mettere nel .h generale
enum command {
	_exi, _print, _list, _save, _load, _new, _help, _TRASP, _add, _sub, _mul
};

void menu(void);

//int parse(void);

int parse(); // da sistemare i parametri

int cmdcheck(int, char**);

msg msetup(int, char**);

int send(void);

int send2(struct msg);

char** tokenizer(char*, int*);

double* tokenizer2(char*);



int main(int argc, char **argv) { // o *argv[]

	int aux = 0;
	//GUARDARE ESERCIZIO SHELL PER lo SWITCH COMANDI
	if (argc != 2) {
		WRITELN("NMAT Client: Errore! Fornire il nome utente!");
		return -1;
	}
	//Se l’utente non viene autenticato,
	//esecuzione di nmatc termina visualizzando
	// un messaggio di errore sullo stderror

	//!!! farne un init() !!!
	pid = getpid();
	username = argv[1];
	login = malloc(30 * sizeof(char));// basta anche meno capire...
	to_server = malloc(30 * sizeof(char));
	from_server = malloc(30 * sizeof(char)); // magari fare na macro per le malloc delle stringhe

	sprintf(to_server, "%s%d", "clientserver", pid);
	WRITE("Utente ");
	WRITE(username);
	WRITELN(" benvenuto nel sistema NMAT!");
	WRITELN("Collegamento al server in corso...");

	//attenzione che va avanti se c'è la pipe rimasta da un crash..
	if ((servpipe = open("clientserver", O_WRONLY)) < 0) { //usare IFERROR
		WRITELN("Errore nell'aprire la la pipe clientserver");
		return -1;
	}

	aux = sprintf(login, "%d%s%s", pid, " CONNECT ", username);//ritorna il numero caratteri
	WRITELN(login);

	//due volte aux etico?
	aux = write(servpipe, login, aux); //scrive se c'è la pipe ma non il server in ascolto
	//free(&aux); //tanto per?
	close(servpipe); // non serve più
	sprintf(from_server, "%s%d", "serverclient", pid);
	mkfifo(from_server, 0644); //creata prima del login
	//chiedere se ok!!
	in = open(from_server, O_RDONLY);// senza non block si blocca perchè viene aperta solo a ricezione msg
	// dal server


	WRITELN("in attesa di autenticazione");
	WRITE("pausa 3 secondi tanto per..");
	sleep(3);
	buffer = malloc(30 * sizeof(char));
	read(in, buffer, 30);
	printf("letto dopo login: !%s!\n", buffer);
	char *auxl;
	auxl = malloc(5 * sizeof(char));
	auxl = strtok(buffer, "LOGIN ");
	printf("auth=%s\n", auxl); //attenzione!! da null a volte
	int login;
	login = atoi(auxl);

	switch (login) { // fare una connect()?

	case 1: {
		WRITELN("Errore: nome utente non valido!");
		exit(1);
		break; //inutili?
	}

	case -1: {
		WRITELN("Errore: utente già connesso al sistema!")
		exit(1);
		break; //inutili?
	}
		//ma vedere se c'è da ripulire cmq!
	}

	WRITE("Utente ");
	WRITE(username);
	WRITELN(" autenticato!");

	//out = open(to_server, O_WRONLY);
	printf("apro la pipe !%s!\n", to_server);
	if ((out = open(to_server, O_RDWR | O_NONBLOCK)) < 0) { //usare IFERROR
		WRITELN("Errore nell'aprire la la pipe TOSERVER"); //pattume da cambiare
		perror("pipe");
		return -1;
	}

	menu();


	close(in);
	close(out);
	unlink(from_server);

	return 0; // temporaneo

	// RICORDARE DI METTERE EXIT_SUCCESS; etc
}

void menu() { // solo per la stampa del menu?
	WRITELN("inizio menù!");
	int run = 1; //nome migliore?

	while (run) {
		printf("in menu chiamo parse()\n");
		run = parse();
		printf("uscita da parse()\n");
	}

//int cammello = parse();
//printf("parse =%d\n",cammello);
//printf("infracammello \n");
//cammello = parse();
//printf("parse 2 =%d\n",cammello);

}


//rimane da vedere che capita alla seconda chiamata


int parse(){ //forse non serva sia funz di tipo int
	int status = 1; //rinominare
	int rd;
	int i = 0;
	int j; //dopo non serve piu ora tant per il for per la stamap tkns
	int wr = 0; //pattume
	int lenght = 0;
	char **tkns;
	int cmd_code;
	char* args[3]; // da spostare fuori parse? // massimo 3 nomi di matrici coinvolte

	//legge la riga poi sistemare..
	while((rd = read(0,cmd,N)) > 0){
		lenght =+ rd;
		cmd[rd-1] = '\0';
	}

	cmd[rd-1] = '\0'; // giustificarlo
	printf("parsing: !%s!\n", cmd);

	tkns = tokenizer(cmd,&i); //spezzo la linea in tokens,
	// ora ho i token, array di stringhe
	printf("tkn con %d stringhe\n",i);
	for (j = 0; j < i; j++){

		printf("tkn[%d]=%s\n",j,tkns[j]);
	}
	printf("fine for tkns\n");
	cmd_code = cmdcheck(i, tkns);
	printf("codice dopo parse = %d\n", cmd_code);





	//prima cosa.. trovare il comando

	return cmd_code;
}


/*
 * il controllo sulla dim delle matrici dove farlo?
 * funz a parte per parsare i double
 */

int cmdcheck(int tnum, char** tkn) {

	//dividere a seconda dei casi
	//prima i casi con comando singolo (display, exit, help)
	switch(tnum) {

	case 1: { //se 1 token [exit,display,help]
		if (strcmp(tkn[0],"exit") == 0)
			return _exi;
		if (strcmp(tkn[0],"help") == 0)
			return _help;
		if (strcmp(tkn[0],"list") == 0)
			return _list;
		else {
			return -1; // define? ;)
		}

	} // fine case 1

	case 2: { 	//se 2 token [print,save,load, o niu (cancellazione mat)
		if (strcmp(tkn[1],"=") == 0) //cancellazione.
				return _new; // fare un codice apposito per questa che tanto cancella?
		if (strcmp(tkn[0],"print") == 0)
				return _print; // e se uno facesse "print new" andrebbe affanculo..
		if (strcmp(tkn[0],"save") == 0)
				return _save;
		if (strcmp(tkn[0],"load") == 0)
				return _load;
		else {
			return -1;
		}

	} // fine case 2

//	case 3: { //forse solo se creo una matrice con 1 solo elemento?
//		// forse non serve rientra nel caso default che tratta solo la niu
//	}

	case 5: {  	//se 5 token [op,trasp]
		if (strcmp(tkn[1],"=") == 0){ // o è una niu di una matrice
			if (strcmp(tkn[3],"TRASP") == 0)
				return _TRASP;
			if (strcmp(tkn[3],"+") == 0)
				return _add;
			if (strcmp(tkn[3],"-") == 0)
				return _sub;
			if (strcmp(tkn[3],"*") == 0)
				return _mul;
		} // tutti i casi con k = x op k

		else { // non c'è = quindi errore
			return -1;
		}



	} //fine case 5

	default: { //considerare lo 0? o considerarlo controllato prima?
		if (strcmp(tkn[1],"=") == 0){
			return _new;
		}
		else {
			return -1;
		}
	}



	} // fine switch

} // fine cmdcheck


/*
 * ora tokenizer fa solo una cosa, spezza la riga in token
 */

char** tokenizer(char* line, int *num){ //forse aggiungere di passare il token da scartare.. per i ;
	int n = 0;
	int allocated = 5;
	char **tokens;
	char skip[] = " \n"; // potrebbe essere da passare a seconda se poi si vuole skippare il ;
	tokens = malloc(allocated *(sizeof(char**)));
	tokens[n] = strtok(line, skip); //controllare la nullità?
	while(tokens[n] != NULL) { // mi par un troiaio
		n++;
		if(n == allocated) {
			allocated *=2;
			printf("realloc di tokens\n");
			tokens = (char**)realloc(tokens, allocated * sizeof(char**)); //o sizeof char*?
		}
		tokens[n]= strtok(NULL, skip);
	}
	*num = n;
	return tokens;
}

msg msetup(int cmd, char** tkns){
	//dai tkns devo estrarre stringhe e numeri
	//ma tutto dipende dal comando
	msg cmd_msg;

	switch(cmd){
		case _exi:{

		}

		case _print:{

		}

		case _list:{

		}

		case _save:{

		}

		case _load:{

		}

		case _new:{

		}

		case _help:{

		}

		case _TRASP:{

		}

		case _add:{

		}

		case _sub:{

		}

		case _mul:{

		}

	} // fine swith generale msetup

} //fine msetup


